#include <kernel/initcall.h>
#include <kernel/syslog.h>
#include <kernel/bus.h>
#include <drivers/uart.h>
#include <drivers/gpio.h>
#include <string.h>
#include <mm/mem.h>
#include <iomode.h>


/**
 * @brief uart bus probe function, this function is used to probe the uart bus
 * @param dev uart device
 * @return: 0: success, -1: failed
 */
static int uart_bus_probe(struct device *dev)
{
    struct uart_device *udev = to_uart_device(dev);
    struct uart_driver *udrv = to_uart_driver(dev->driver);

    if(udrv && udrv->probe) {
        return udrv->probe(udev);
    }

    return 0;
}


/**
 * @brief uart bus remove function, this function is used to remove the uart bus
 * @param dev uart device
 * @return: none
 */
static void uart_bus_remove(struct device *dev)
{
    struct uart_device *udev = to_uart_device(dev);
    struct uart_driver *udrv = to_uart_driver(dev->driver);

    if(udrv->remove) {
        udrv->remove(udev);
    }
}


/**
 * uart bus struct, used to register the uart bus
 */
struct bus_type uart_bus = {
    .name = "uart",
    .match = bus_simple_match,
    .probe = uart_bus_probe,
    .remove = uart_bus_remove,
};


/**
 * @brief uart bus register function, this function is used to register the uart bus
 * @param none
 * @return: 0: success, -1: failed
 */
static int uart_bus_register(void)
{
    return bus_register(&uart_bus);
}


base_initcall(uart_bus_register);


/**
 * @brief get uart gpio from fdt
 * @param node fdt node
 * @param pin uart gpio
 * @return 0 on success, -1 on error
 * @note: you should add uart pins(tx,rx) into uart master device tree node, for example:
 *        uart1:
 *            ...
 *            tx-gpio: 9
 *            rx-gpio: 10
 *            ...
 */
int uart_master_get_gpio_from_fdt(fdt_node_t *node, struct uart_gpio *pin)
{
    size_t afio, tx_pin, rx_pin;
    if(fdt_read_prop_int(node, "afio", &afio)) {
        UART_SYSLOG_ERROR("%s: not found afio", node->name);
        return -1;
    }
    
    if(fdt_read_prop_int(node, "tx-gpio", &tx_pin)) {
        UART_SYSLOG_ERROR("%s: not found tx pin", node->name);
        return -1;
    }
    if(gpio_request(tx_pin)) {
        UART_SYSLOG_ERROR("%s: tx gpio request failed", node->name);
        return -1;
    }
    UART_DEBUG_TRACE("%s: tx gpio(%d) request success", node->name, tx_pin);

    pin->tx = tx_pin;
    gpio_set_mux(tx_pin, (IO_MODE_UART_TX << 8) | afio);

    if(fdt_read_prop_int(node, "rx-gpio", &rx_pin)) {
        UART_SYSLOG_ERROR("%s: not found rx pin", node->name);
        return -1;
    }
    if(gpio_request(rx_pin)) {
        UART_SYSLOG_ERROR("%s: rx gpio request failed", node->name);
        return -1;
    }
    UART_DEBUG_TRACE("%s: rx gpio(%d) request success", node->name, rx_pin);
    
    pin->rx = rx_pin;
    gpio_set_mux(rx_pin, (IO_MODE_UART_RX << 8) | afio);
    
    return 0;
}
